package lol.clann.minecraft.springboot.core.condition;

import lol.clann.minecraft.springboot.api.annotation.condition.ConditionalOnMinecraftVersion;
import lol.clann.minecraft.springboot.bukkit.utils.BukkitUtils;
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.MethodMetadata;

import java.util.StringJoiner;

/**
 *
 *
 * {@link Condition} that checks if properties are defined in environment.
 *
 * @author Maciej Walkowiak
 * @author Phillip Webb
 * @author Stephane Nicoll
 * @author Andy Wilkinson
 * @since 1.1.0
 * @see ConditionalOnMinecraftVersion
 */
@Order(Ordered.HIGHEST_PRECEDENCE + 39)
public class OnMinecraftVersionCondition extends SpringBootCondition {

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String className = getClassName(metadata);
        if (ConditionalOnMinecraftVersion.class.getName().equals(className)) {
            return ConditionOutcome.match();
        }
        AnnotationAttributes attr = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(ConditionalOnMinecraftVersion.class.getName()));
        AnnotationAttributes[] ranges = attr.getAnnotationArray("value");
        StringJoiner sj = new StringJoiner(", ");
        for (AnnotationAttributes range : ranges) {
            int min = range.getNumber("min");
            int max = range.getNumber("max");
            if (min <= BukkitUtils.getBukkitVersionNumber() && max > BukkitUtils.getBukkitVersionNumber()) {
                return ConditionOutcome.match();
            }
            sj.add("[" + min + "-" + max + "]");
        }
        return ConditionOutcome.noMatch(ConditionMessage.of(sj.toString()));
    }

    private static String getClassName(AnnotatedTypeMetadata metadata) {
        String className;
        if (metadata instanceof ClassMetadata) {
            ClassMetadata classMetadata = (ClassMetadata) metadata;
            className = classMetadata.getClassName();
        } else {
            MethodMetadata methodMetadata = (MethodMetadata) metadata;
            className = methodMetadata.getDeclaringClassName();
        }
        return className;
    }

}
